/**
 * 
 */

package com.shy.base.util;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import com.shy.base.vo.EntityTypeValue;
import com.shy.base.vo.QueryParamVo;

/**
 * <p>
 * Title:通过实体对象组装Hql
 * </p>
 * <p>
 * Description:
 * </p>
 * <p>
 * Company:ipebg
 * </p>
 * 
 * @author shy
 * @date 2016-8-24 上午09:23:51
 */
@SuppressWarnings("rawtypes")
public class ObjectToWhereHql {
	
    /**
     * <p>
     * Description:通过反射自动拼装参数map
     * </p>
     * 
     * @param obj
     *            实体对象
     * @param alias
     *            别名 用于拼接到jql语句中，如不需要设置null
     * @return
     */
    public static QueryParamVo buildWhereHql(Object obj, String alias) {
        Map<String, EntityTypeValue> map = getObjectToMap(obj, alias, null, 
                null, null, null);
        return buildHqlParams(map);
    }

    /**
     * <p>
     * Description:通过反射自动拼装参数map
     * </p>
     * @param obj
     *            实体对象
     * @param alias
     *            别名 用于拼接到jql语句中，如不需要设置null
     * @param unusedTypes
     *            不作查询条件的参数列表{"type1","type2","type2","type2"}
     * @param likeTypes
     *            模糊匹配查询条件的参数列表{"type1","type2","type2","type2"}
     * @return key:whereHql value:params
     * @author shy
     * @date 2016-4-28 上午09:53:13
     */
    public static QueryParamVo buildWhereHql(Object obj, String alias,
            String[] unusedTypes, String[] likeTypes) {
        Map<String, EntityTypeValue> map = getObjectToMap(obj, alias, unusedTypes,
                likeTypes, null, null);
        return buildHqlParams(map);
    }

    /**
     * <p>
     * Description:通过反射自动拼装参数map
     * </p>
     * @param obj
     *            实体对象
     * @param alias
     *            别名 用于拼接到jql语句中，如不需要设置null
     * @param unusedTypes
     *            不作查询条件的参数列表{"type1","type2","type2","type2"}
     * @param likeTypes
     *            模糊匹配查询条件的参数列表{"type1","type2","type2","type2"}
     * @param preLikeTypes
     *            前缀模糊匹配查询条件的参数列表{"type1","type2","type2","type2"},匹配以参数开头的内容
     * @param sufLikeTypes
     *            后缀模糊匹配查询条件的参数列表{"type1","type2","type2","type2"},匹配以参数结尾的内容
     * @return key:whereHql value:params
     */
    public static QueryParamVo buildWhereHql(Object obj, String alias,
            String[] unusedTypes, String[] likeTypes, 
            String[] preLikeTypes, String[] sufLikeTypes) {
        Map<String, EntityTypeValue> map = getObjectToMap(obj, alias, unusedTypes,
                likeTypes, preLikeTypes, sufLikeTypes);
        return buildHqlParams(map);
    }

    /**
     * <p>
     * Description:通过反射自动拼装参数map
     * </p>
     * 
     * @param obj
     *            实体对象
     * @param alias
     *            别名 用于拼接到jql语句中，如不需要设置null
     * @param unusedTypes
     *            不作查询条件的参数列表{"type1","type2","type2","type2"}
     * @param preLikeTypes
     *            前缀模糊匹配查询条件的参数列表{"type1","type2","type2","type2"}
     * @return key:whereHql value:params
     */
    public static QueryParamVo buildCriteriaAndPreLike(Object obj, String alias,
            String[] unusedTypes, String[] preLikeTypes) {
        Map<String, EntityTypeValue> map = getObjectToMap(obj, alias, unusedTypes, null,
                preLikeTypes, null);
        return buildHqlParams(map);
    }

    /**
     * <p>
     * Description:通过反射自动拼装参数map
     * </p>
     * 
     * @param obj
     *            实体对象
     * @param alias
     *            别名 用于拼接到jql语句中，如不需要设置null
     * @param unusedTypes
     *            不作查询条件的参数列表{"type1","type2","type2","type2"}
     * @param sufLikeTypes
     *            后缀模糊匹配查询条件的参数列表{"type1","type2","type2","type2"},匹配以参数结尾的内容
     * @return key:whereHql value:params
     */
    public static QueryParamVo buildCriteriaAndSufLike(Object obj, String alias,
            String[] unusedTypes, String[] sufLikeTypes) {
        Map<String, EntityTypeValue> map = getObjectToMap(obj, alias, unusedTypes, null,
                null, sufLikeTypes);
        return buildHqlParams(map);
    }

    /**
     * <p>
     * Description:通过反射自动拼装参数map
     * </p>
     * 
     * @param obj
     *            :实体对象
     * @param clazz
     *            :类
     * @param alias
     *            :别名 用于拼接到jql语句中，如不需要设置null
     * @param unusedTypes
     *            :不作查询条件的参数列表{"type1","type2","type2","type2"}
     * @param likeTypes
     *            :模糊匹配查询条件的参数列表{"type1","type2","type2","type2"}
     * @param preLikeTypes
     *            :前缀模糊匹配查询条件的参数列表{"type1","type2","type2","type2"}
     * @param sufLikeTypes
     *            :后缀模糊匹配查询条件的参数列表{"type1","type2","type2","type2"}
     * @author shy
     * @date 2016-4-28 上午09:53:13
     */
    private static Map<String, EntityTypeValue> getObjectToMap(Object obj, String alias, String[] unusedTypes, 
    		String[] likeTypes, String[] preLikeTypes, String[] sufLikeTypes) {
        Map<String, EntityTypeValue> map = new HashMap<String, EntityTypeValue>();
        if (obj != null) {
            try {
                List<String> unusedTypeList = null == unusedTypes ? new ArrayList<String>()
                        : Arrays.asList(unusedTypes);
                List<String> likeTypeList = null == likeTypes ? new ArrayList<String>() : Arrays
                        .asList(likeTypes);
                List<String> preLikeTypeList = null == preLikeTypes ? new ArrayList<String>()
                        : Arrays.asList(preLikeTypes);
                List<String> sufLikeTypeList = null == sufLikeTypes ? new ArrayList<String>()
                        : Arrays.asList(sufLikeTypes);
                Class clazz = obj.getClass();
                //Field[] fields = clazz.getDeclaredFields();
                //Field[] fields = clazz.getFields();
                
                List<Field> fieldList = new ArrayList<>() ;
                Class tempClass = clazz;
                while (tempClass != null && !tempClass.getName().toLowerCase().equals("java.lang.object")) {//当父类为null的时候说明到达了最上层的父类(Object类).
                	fieldList.addAll(Arrays.asList(tempClass .getDeclaredFields()));
                	tempClass = tempClass.getSuperclass(); //得到父类,然后赋给自己
                }
                
                for (Field f : fieldList) {
                    f.setAccessible(true);
                    // 判断属性值是否为null，是否在不參與查询的属性列表中
                    if (f.get(obj) != null && !"serialVersionUID".equals(f.getName()) && !unusedTypeList.contains(f.getName())) {
                        String aliasPre = null == alias || "".equals(alias.trim()) ? "" : alias + ".";
                        if (!f.get(obj).equals("")) {
                            EntityTypeValue etv = new EntityTypeValue();
                            if (likeTypeList.contains(f.getName())) {
                                etv.setParamPrefix("like");
                            } else if (preLikeTypeList.contains(f.getName())) {
                                etv.setParamPrefix("preLike");
                            } else if (sufLikeTypeList.contains(f.getName())) {
                                etv.setParamPrefix("sufLike");
                            }
                            etv.setParamType("basic");
                            etv.setParamValue(f.get(obj));
                            etv.setParamName(f.getName());
                            map.put(aliasPre + f.getName(), etv);
                        }
                    }
                }
                return map;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return map;
    }

    /**
     * <p>
     * Description:通过绑定名称传参拼接hql，同时将参数放到list中
     * </p>
     * 
     * @param map
     *            参数构造器map
     * @author shy
     * @date 2016-4-28 上午11:18:30
     */
    private static QueryParamVo buildHqlParams(Map<String, EntityTypeValue> map) {
        if (map.size() > 0) {
            Iterator iter = map.entrySet().iterator();
            String hql = "";
            List<EntityTypeValue> params = new ArrayList<EntityTypeValue>();
            while (iter.hasNext()) {
                Entry e = (Entry) iter.next();
                hql += "".equals(hql) ? "" : " and ";
                // 如果设置了别名如s.name,参数名设置规则为name 需要截取
                String paramName = e.getKey().toString().indexOf(".") != -1 ? e
                        .getKey()
                        .toString()
                        .substring(e.getKey().toString().indexOf(".") + 1,
                                e.getKey().toString().length()) : e.getKey().toString();
                // like 字段 模糊匹配
                if (null != ((EntityTypeValue) e.getValue()).getParamPrefix()
                        && "like".equals(((EntityTypeValue) e.getValue()).getParamPrefix())) {
                    hql += (String) e.getKey() + " like :" + paramName;
                    EntityTypeValue etv = (EntityTypeValue) e.getValue();
                    etv.setParamValue("%" + etv.getParamValue() + "%");
                    params.add(etv);
                } else if (null != ((EntityTypeValue) e.getValue()).getParamPrefix()
                        && "preLike".equals(((EntityTypeValue) e.getValue()).getParamPrefix())) {
                    hql += (String) e.getKey() + " like :" + paramName;
                    EntityTypeValue etv = (EntityTypeValue) e.getValue();
                    etv.setParamValue(etv.getParamValue() + "%");
                    params.add(etv);
                } else if (null != ((EntityTypeValue) e.getValue()).getParamPrefix()
                        && "sufLike".equals(((EntityTypeValue) e.getValue()).getParamPrefix())) {
                    hql += (String) e.getKey() + " like :" + paramName;
                    EntityTypeValue etv = (EntityTypeValue) e.getValue();
                    etv.setParamValue(etv.getParamValue() + "%");
                    params.add(etv);
                } else {
                    // 普通字段 = 全值匹配
                    hql += (String) e.getKey() + "=:" + paramName;
                    params.add((EntityTypeValue) e.getValue());
                }
            }
            QueryParamVo qpv = new QueryParamVo();
            qpv.setParams(params);
            qpv.setWhereHql(hql);
            return qpv;
        }
        return null;
    }

}
